package db

import (
	"context"

	"github.com/neo4j/neo4j-go-driver/v5/neo4j"
)

const getUserByID = `
MATCH (u:User)
WHERE elementId(u) = $uuid
RETURN u
`

func (dao *DAO) GetUserByID(ctx context.Context, uuid string) (User, error) {
	var i User
	argMap, err := NewParamConverter(&uuid).AsMap()
	if err != nil {
		return i, err
	}
	result, err := dao.db.ExecuteQuery(ctx, getUserByID, argMap, neo4j.ExecuteQueryWithDatabase(dao.dbName))
	if err != nil {
		return i, err
	}
	err = NewNodeLoader(&i).LoadE(ctx, result, "u")
	if err != nil {
		return i, err
	}
	return i, err
}

const listUsersWithRole = `
Match (u:User) -[:BELONGS_TO]- (r:Role) 
WITH u, collect(r.name) as roles 
RETURN elementId(u) as elementId, u.name as name, roles
`

func (dao *DAO) ListUsersWithRoles(ctx context.Context) ([]*UserWithRole, error) {
	var i []*UserWithRole
	argMap, err := NewParamConverter(&NoArg).AsMap()
	if err != nil {
		return i, err
	}
	result, err := dao.db.ExecuteQuery(ctx, listUsersWithRole, argMap, neo4j.ExecuteQueryWithDatabase(dao.dbName))
	if err != nil {
		return i, err
	}
	loader := NewQueryLoader[UserWithRole](uint(len(result.Records)))
	err = loader.LoadE(ctx, result)
	if err != nil {
		return i, err
	}
	i = loader.Output()
	dao.db.slog.Infof("rows=>%d", len(i))
	return i, nil
}

const pagedUsersWithRole = `
Match(u:User) -[:BELONGS_TO]- (r:Role)
WITH count(u) as total
Match(u:User) -[:BELONGS_TO]- (r:Role) 
WITH u, collect(r.name) as roles, total
ORDER By u.name DESC SKIP $skip LIMIT $limit
WITH collect(u{elementId: elementId(u), .name, roles}) as rows,total
RETURN rows,total
`

func (dao *DAO) PagedUsersWithRoles(ctx context.Context, pager Pager) (Paged[UserWithRole], error) {
	var i Paged[UserWithRole]
	argMap, err := NewParamConverter(&NoArg).WithPager(&pager).AsMap()
	if err != nil {
		return i, err
	}
	result, err := dao.db.ExecuteQuery(ctx, pagedUsersWithRole, argMap, neo4j.ExecuteQueryWithDatabase(dao.dbName))
	if err != nil {
		return i, err
	}
	loader := NewPagedQueryLoader(&i)
	err = loader.LoadE(ctx, result)
	if err != nil {
		return i, err
	}
	return i, nil
}
